package com.nulldev.util.web.YouTubeExtractor.playlist;

import java.util.List;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.data.variable;
import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.internal.backport.concurrency9.Lists;
import com.nulldev.util.io.FastIO.FastIO;
import com.nulldev.util.languages.json.uniapi.UniJsonIterableValue;
import com.nulldev.util.languages.json.uniapi.UniJsonValue;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.HttpClient.HttpClient;
import com.nulldev.util.web.HttpClient.HttpResponse;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractor;
import com.nulldev.util.web.YouTubeExtractor.extractors.util.SharedExtractorUtil;

public class YTPlaylistExtractor {

	private static final Logger log = LoggerFactory.getLogger();

	public static class YTPlaylistEntry {
		public final String title;
		public final String videoID;
		public final String author;
		public final long duration;
		public final long index;

		public YTPlaylistEntry(final String title, final String videoID, final String author, final long duration, final long index) {
			this.title = title;
			this.videoID = videoID;
			this.author = author;
			this.duration = duration;
			this.index = index;
		}
	}

	public static class YTPlaylist {
		public final String title;
		public final List<YTPlaylistEntry> entries;
		public final String continuation;

		public YTPlaylist(final String title, final List<YTPlaylistEntry> entries, final String continuation) {
			this.title = title;
			this.entries = entries;
			this.continuation = continuation;
		}

		public boolean hasContinuation() {
			return !StringsUtil.isBlank(this.continuation);
		}

		public String getContinuation() {
			return this.continuation;
		}
	}

	public static YTPlaylist getPlaylist(final String playlistID) throws Exception {
		return getPlaylist(playlistID, true);
	}

	public static YTPlaylist getPlaylist(final String playlistID, final boolean sendConsentCookie) throws Exception {
		if (playlistID == null || playlistID.isEmpty()) {
			return new YTPlaylist(null, Lists.of(), null);
		}
		/* Cookie consent is mandatory. */
		final HttpResponse<String> o = HttpClient.getString().url("https://www.youtube.com/playlist?list=" + playlistID)
				.headers(sendConsentCookie ? YouTubeExtractor.DEFAULT_COOKIES2 : YouTubeExtractor.BLANK_COOKIES).create();
		final String d = o.dataThenClose();
		final UniJsonValue yte = SharedExtractorUtil.getYTInitialData(d).waitTillCompletion();
		if (yte == null) {
			log.info(d);
			FastIO.get().flush();
			throw new NullPointerException("Failed to parse!");
		}
		final String playlistTitle = yte.mget("microformat.microformatDataRenderer").getString("title");
		final UniJsonIterableValue playlistEntries = yte.get("contents").get("twoColumnBrowseResultsRenderer").get("tabs").get(0).get("tabRenderer")
				.get("content").get("sectionListRenderer").get("contents").get(0).get("itemSectionRenderer").get("contents").get(0)
				.get("playlistVideoListRenderer").get("contents").asArray();
		final List<YTPlaylistEntry> entries = FastLists.list(playlistEntries.size());
		final variable<String> cont = new variable<String>(null);
		playlistEntries.forEach((entry) -> {
			if (entry.contains("playlistVideoRenderer")) {
				final UniJsonValue video = entry.get("playlistVideoRenderer");
				final long videoIndex = video.get("navigationEndpoint").get("watchEndpoint").getLong("index");
				entries.add(new YTPlaylistEntry(video.get("title").get("runs").get(0).getString("text"), video.getString("videoId"),
						video.get("shortBylineText").get("runs").get(0).getString("text"), video.getLong("lengthSeconds"), videoIndex));
			} else if (entry.contains("continuationItemRenderer")) {
				final UniJsonValue continuationItemRenderer = entry.get("continuationItemRenderer");
				cont.set(continuationItemRenderer.get("continuationEndpoint").get("continuationCommand").getString("token"));
			} else {
				log.warn("Unknown object: " + entry);
			}
		});
		return new YTPlaylist(playlistTitle, entries, cont.get());
	}

	public static void main(String[] args) throws Exception {
		final YTPlaylist ytpl = getPlaylist("PLggwHaWkdoiaVwHQ7rfGtOpRTJ1__rFR_");
		JVM.println(ytpl.title + " - " + ytpl.continuation);
		ArrayUtils.printLln(ytpl.entries);
	}
}
